/*******************************************************************************
* Copyright 2011 André Rouél
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package net.sf.jacclog.service.analyzer.commands.internal;
import java.io.IOException;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;
import net.sf.jacclog.api.LogEntryService;
import net.sf.jacclog.api.domain.ReadableLogEntry;
import net.sf.jacclog.api.domain.http.ReadableHttpRequestHeaderField;
import net.sf.jacclog.api.domain.http.ReadableHttpResponseHeaderField;
import net.sf.jacclog.service.analyzer.LogEntryAnalysisResult;
import net.sf.jacclog.service.analyzer.LogEntryAnalyzer;
import net.sf.jacclog.uasparser.UserAgentInfo;
import org.apache.felix.gogo.commands.Command;
import org.apache.felix.gogo.commands.Option;
import org.apache.karaf.shell.console.OsgiCommandSupport;
import org.joda.time.DateTime;
import org.joda.time.Interval;
import org.joda.time.Period;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.PeriodFormatter;
import org.joda.time.format.PeriodFormatterBuilder;
/**
* Command to analyze log entries for a specific day or within a specified period.
*
* <strong>Examples:</strong><br>
* <code>analyze -f 2011-08-28</code> or<br>
* <code>analyze -f 2011-08-28 -t 2011-08-30</code>
*
* @author André Rouél
*/
@Command(scope = "jacclog", name = "analyze", description = "Analyzes log entries of a specific day or within a specified period.")
@SuppressWarnings("PMD.SystemPrintln")
public class AnalyzeLogEntriesShellCommand extends OsgiCommandSupport {
/**
* Separator for the period formatter
*/
private static final String SEPARATOR = " ";
/**
* Formatter to format the elapsed time (period) to import log entries
*/
private static final PeriodFormatter FORMATTER = new PeriodFormatterBuilder().printZeroRarelyLast().appendHours()
.appendSuffix("H").appendSeparator(SEPARATOR).appendMinutes().appendSuffix("m").appendSeparator(SEPARATOR)
.appendSeconds().appendSuffix("s").appendSeparator(SEPARATOR).appendMillis().appendSuffix("ms")
.toFormatter();
/**
* Requests an user input to proceed with the analysis.
*
* @param count
* @return
*/
private static boolean proceed(final long count) {
int inChar;
System.out.println("Do you really want to analyze " + count + " log entries (y/n):");
boolean result = false;
try {
inChar = System.in.read();
if (inChar == 121 || inChar == 89) {
result = true;
}
} catch (final IOException e) {
System.out.println("Error reading an answer from user.");
}
return result;
}
private LogEntryService<ReadableLogEntry<ReadableHttpRequestHeaderField, ReadableHttpResponseHeaderField>> service;
private LogEntryAnalyzer analyzerService;
@Option(name = "-f", aliases = "--from", description = "The day to be analyzed or the start date of the interval.", required = true, multiValued = false)
private final String from = null;
@Option(name = "-t", aliases = "--to", description = "The end date of the interval. This option must be used in conjunction with option '-f'.", required = false, multiValued = false)
private final String to = null;
private void analyzeEntries() {
if (service != null) {
final DateTimeFormatter format = DateTimeFormat.forPattern("yyyyMMdd");
final DateTime from = format.parseDateTime(this.from);
final DateTime to = (this.to != null) ? format.parseDateTime(this.to) : from.plusDays(1);
final Interval interval = new Interval(from, to);
final Period period = interval.toPeriod();
final StringBuffer buffer = new StringBuffer();
buffer.append("Analyse the log entries from '");
buffer.append(from.toString()).append('\'');
buffer.append(" to '").append(to);
// print the period
final String space = " ";
buffer.append("'. The period includes ");
final PeriodFormatter dateFormat = new PeriodFormatterBuilder().appendYears()
.appendSuffix(" year", " years").appendSeparator(space).appendMonths()
.appendSuffix(" month", " months").appendSeparator(space).appendWeeks()
.appendSuffix(" week", " weeks").appendSeparator(space).appendDays().appendSuffix(" day", " days")
.appendSeparator(space).appendHours().appendSuffix(" hour", " hours").appendSeparator(space)
.appendMinutes().appendSuffix(" minute", " minutes").appendSeparator(space).toFormatter();
dateFormat.printTo(buffer, period);
buffer.append('.');
System.out.println(buffer.toString());
final long maxResults = service.count(interval);
if (maxResults > 0) {
int maxCount = 0;
if (proceed(maxResults)) {
final long startTime = System.currentTimeMillis();
final LogEntryAnalysisResult result = analyzerService.analyze(interval).toResult();
final Map<UserAgentInfo, AtomicInteger> stats = result.getUserAgentInfos();
System.out.println("User agent information count: " + stats.size());
String name;
String osName;
int count;
for (final Entry<UserAgentInfo, AtomicInteger> entry : stats.entrySet()) {
name = entry.getKey().getName();
osName = entry.getKey().getOsName();
count = entry.getValue().get();
maxCount += count;
System.out.println(name + " (" + osName + ") \t" + count);
}
System.out.println("Sum: " + maxCount);
final long elapsedTime = System.currentTimeMillis() - startTime;
final Period p = new Period(elapsedTime);
System.out.println("Total processing time: " + p.toString(FORMATTER));
}
} else {
System.out.println("There is nothing to analyze.");
}
}
}
@Override
protected Object doExecute() throws Exception {
if (service != null) {
analyzeEntries();
} else {
log.warn("Can not analyze the log entries from '" + from + "' to '" + to + "'.");
}
return null;
}
public LogEntryAnalyzer getAnalyzerService() {
return analyzerService;
}
public LogEntryService<ReadableLogEntry<ReadableHttpRequestHeaderField, ReadableHttpResponseHeaderField>> getRepositoryService() {
return service;
}
public void setAnalyzerService(final LogEntryAnalyzer analyzerService) {
this.analyzerService = analyzerService;
}
public void setRepositoryService(
final LogEntryService<ReadableLogEntry<ReadableHttpRequestHeaderField, ReadableHttpResponseHeaderField>> service) {
this.service = service;
}
}